#include "netsocket.h"
#include <QDebug>

NetSocket::NetSocket()
{

}

NetSocket::~NetSocket()
{
    socketStop();
}

void NetSocket::socketStart()
{
    switch (protocol) {
        case TCP_SERVER : {
            tcpServerSock = new QTcpServer();
            tcpServerSock->listen(QHostAddress::AnyIPv4, port);
            isOnline = true;
            connect(tcpServerSock, SIGNAL(newConnection()), this, SLOT(tcpServerNewConnection()));
        } break;
        case TCP_CLIENT: {
            curClient = new QTcpSocket();
            curClient->abort();
            curClient->connectToHost(ipAddr, port);
            isOnline = true;
            clientList.append(curClient);
            connect(curClient, SIGNAL(readyRead()), this, SLOT(readData()));
            connect(curClient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(tcpClientErr(QAbstractSocket::SocketError)));
        } break;
        case UDP : {
            udpSock = new QUdpSocket();
            udpSock->bind(QHostAddress::AnyIPv4, port);
            connect(udpSock, SIGNAL(readyRead()), this, SLOT(readData()));
            isOnline = true;
        } break;
        default : break;
    }
}

void NetSocket::socketStop()
{
    switch (protocol) {
        case TCP_SERVER : {
            QTcpSocket *client;

            foreach (client, clientList) {
                client->close();
                clientList.removeOne(client);
            }
            isOnline = false;
            if (tcpServerSock != Q_NULLPTR) {
                tcpServerSock->close();
                delete tcpServerSock;
                tcpServerSock = Q_NULLPTR;
            }
        } break;
        case TCP_CLIENT : {
            if ((isOnline) && (curClient != Q_NULLPTR)) {
                curClient->close();
                delete curClient;
                curClient = Q_NULLPTR;
                isOnline = false;
                clientList.clear();
            }
        } break;
        case UDP : {
            udpSock->close();
            delete udpSock;
            udpSock = Q_NULLPTR;
            isOnline = false;
        } break;
        default :  break;
    }
}

void NetSocket::tcpServerNewConnection()
{
    curClient = tcpServerSock->nextPendingConnection();
    if (curClient != Q_NULLPTR) {
        connect(curClient,SIGNAL(readyRead()),this,SLOT(readData()));
        connect(curClient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(tcpServerAccepterr(QAbstractSocket::SocketError)));
        clientList.append(curClient);
    }

    emit socketChanged();
}

void NetSocket::tcpServerAccepterr(QAbstractSocket::SocketError socketError)
{
    if (socketError == QAbstractSocket::RemoteHostClosedError) {
        QTcpSocket *clientPtr = qobject_cast<QTcpSocket *>(sender());
        clientPtr->close();
        clientList.removeOne(clientPtr);

        emit socketChanged();
    }
}

void NetSocket::tcpClientErr(QAbstractSocket::SocketError socketError)
{
    Q_UNUSED(socketError);

    if ((isOnline) && (curClient != Q_NULLPTR)) {
        curClient->close();
        isOnline = false;
        clientList.clear();
        emit socketChanged();
    }
}

void NetSocket::readData()
{
    QByteArray readBuf;

    if (protocol == UDP) {
        readBuf.resize(udpSock->pendingDatagramSize());
        udpSock->readDatagram(readBuf.data(), readBuf.size(), &udpClient.ip, &udpClient.port);
        emit socketChanged();
    } else {
        QTcpSocket *clientPtr = qobject_cast<QTcpSocket *>(sender());
        readBuf = clientPtr->readAll();
    }

    if (!readBuf.isEmpty()) {
        tcpData.append(readBuf);

        emit readDone();
    }
}
